/***************************************
 Felipe L Amado       6797205
 Renato A V Nishimori 5121731
 *****************************************/

#ifndef MONITOR_H_
#define MONITOR_H_

#include <semaphore.h>
#include <stdlib.h>
#include <fcntl.h>
#include <vector>
#include <queue>
#include <iostream>
#include <sstream>

using namespace std;

#define CARRO_CHEIO 			0
#define PRONTO_PARA_SAIR 		1
#define PODE_EMBARCAR 			2
#define PODE_DESEMBARCAR 		3
#define PROXIMO_PODE_CARREGAR 	4
#define TEM_QUEM_EMBARCAR		5

class Passageiro {
public:
	int id;
	int bilheteDourado;
	int tempoDeChegada;
	int vez;

	Passageiro () {}

	Passageiro (int id, int bilheteDourado) {
		this->id = id;
		this->bilheteDourado = bilheteDourado;
		this->vez = 0;
		this->tempoDeChegada = 0;
	}

	string str() {
		stringstream ss;
		ss << "Passageiro (id=" << id;
		ss << ",bilheteDourado=" << bilheteDourado;
		ss << ",tempoDeChegada=" << tempoDeChegada;
		ss << ",vez=" << vez;
		ss << ")";
		return ss.str();
	}
};

class ComparePassageiro {
public:
    bool operator()(Passageiro& p1, Passageiro& p2) {
       if (p1.bilheteDourado == 0 && p2.bilheteDourado == 1) return true;
       if (p1.bilheteDourado == p2.bilheteDourado && p1.tempoDeChegada >= p2.tempoDeChegada) return true;
       return false;
    }
};

class Monitor {
private:
	int numeroCarros;
	int capacidade;
	int *passageirosNoCarro;
	bool esperandoPassageiros;
	int carroAtualADescarregar;
	int carroAtualACarregar;
	int proximoCarroACarregar;
	int tempo;

	sem_t *mutex;
	sem_t *carroCheio;
	sem_t *prontoParaSair;
	sem_t *podeEmbarcar;
	sem_t *podeDesembarcar;
	sem_t *proximoCarroPodeCarregar;
	sem_t *temQuemEmbarcar;

	int passCont;
	vector < sem_t* > semDoPassageiro;
	priority_queue <Passageiro, vector<Passageiro>, ComparePassageiro> filaDeP;

	int esperandoEmbarcar;
	int * carroAndando;
	stringstream ** passDentroDoCarro;

	void wait(int cv);
	void wait(int cv, Passageiro rank);
	void signal(int cv);
	void signal_all(int cv);
	int empty(int cv);
	Passageiro minrank(int cv);
	void imprimeEstado();

public:
	Monitor(int numeroCarros, int capacidade);
	~Monitor();
	void pegaCarona(Passageiro pass);
	void carrega();
	void descarrega();

};

#endif /* MONITOR_H_ */
